﻿using HalconDotNet;
using MachineVision.Core.TemplateMatch;
using MachineVision.Shared.Extensions;
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;

namespace MachineVision.Shared.Controls
{
    //Control 类是所有用户界面（UI）控件的基础类，它提供了一系列共通的功能和属性。当你创建一个自定义控件，并且让这个控件继承自 Control 类，你的控件就自动继承了这些功能和属性。
    public class ImageEditView : Control
    {  
        //用于显示图像与图像互动
        private HSmartWindowControlWPF hSmart;
        //用于显示图像与绘图
        private HWindow hWindow;
        private TextBlock txtMsg;

        #region 附加属性Image
        public HObject Image
        {
            get { return (HObject)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }

        public static readonly DependencyProperty ImageProperty =
            DependencyProperty.Register("Image", typeof(HObject), typeof(ImageEditView), new PropertyMetadata(IamgeChagedCallBack));

        private static void IamgeChagedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //首先检查触发回调的DependencyObject是否是ImageEditView类型的实例。
            //接下来，如果e.NewValue（代表属性更新后的新值）不为空，说明Image属性已经被设置了新的HObject（HALCON图像）值。
            if (d is ImageEditView view && e.NewValue != null)
            {
                //调用在ImageEditView上定义的实例方法Display，将新的图像显示在控件对应的HALCON窗口中。
                view.Display((HObject)e.NewValue);
            }
        }
        #endregion

        #region 附加属性DrawObjectList 绘制的形状集合
        public ObservableCollection<DrawingObjectInfo> DrawObjectList
        {
            get { return (ObservableCollection<DrawingObjectInfo>)GetValue(DrawObjectListProperty); }
            set { SetValue(DrawObjectListProperty, value); }
        }

        public static readonly DependencyProperty DrawObjectListProperty =
            //new ObservableCollection<DrawingObjectInfo>()。指定了属性的初始默认值。
            DependencyProperty.Register("DrawObjectList", typeof(ObservableCollection<DrawingObjectInfo>), typeof(ImageEditView), new PropertyMetadata(new ObservableCollection<DrawingObjectInfo>()));
        #endregion

        #region 附加属性MatchResults
        public MatchResult MatchResult
        {
            get { return (MatchResult)GetValue(MatchResultProperty); }
            set { SetValue(MatchResultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MatchResultProperty =
            DependencyProperty.Register("MatchResult", typeof(MatchResult), typeof(ImageEditView), new PropertyMetadata(MatchResultCallBack));

        public static void MatchResultCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ImageEditView view && e.NewValue != null)
            {
                view.DisplayMatchRender();
            }
        }

        private void DisplayMatchRender()
        {
            if (Image != null) 
            { 
                Display(Image); 
            }

            if (MatchResult != null && MatchResult.Results!=null)
            {
                foreach (var item in MatchResult.Results)
                {
                    if (MatchResult.Setting.IsShowCenter)
                    {
                        hWindow.DispCross(item.Row, item.Column, 30, item.Angle);
                    }

                    if (MatchResult.Setting.IsShowDisplayText)
                    {
                        hWindow.SetString($"({Math.Round(item.Row,2)},{Math.Round(item.Column,2)})", "image", item.Row, item.Column, "black", "true");
                    }

                    if (MatchResult.Setting.IsShowMatchRange)
                    {
                        hWindow.DispObj(item.Contours);
                    }
                }
            }
        }
        #endregion

        #region 附加属性MaskObject 掩膜
        public HObject MaskObject
        {
            get { return (HObject)GetValue(MaskObjectProperty); }
            set { SetValue(MaskObjectProperty, value); }
        }

        public static readonly DependencyProperty MaskObjectProperty =
            DependencyProperty.Register("MaskObject", typeof(HObject), typeof(ImageEditView), new PropertyMetadata(null));

        #endregion

        /// <summary>
        /// Display 方法：接收一个 HObject（图像）参数，通过 hWindow.DispObj 方法在 hWindow 上显示该图像。
        /// </summary>
        /// <param name="newValue">HObject（图像）参数</param>
        private void Display(HObject newValue)
        {
            //在HALCON的图形显示窗口（hWindow）中显示一个图像或图形对象（newValue）
            hWindow.DispObj(newValue);
            //用来设置窗口的可视区域，即决定图像或图形对象在窗口中的显示方式。
            //SetPart方法的参数为(row1, col1, row2, col2)，分别代表窗口可视区域的起始行、起始列、终止行和终止列。
            //这里的参数 0, 0, -2, -2 意味着图像的显示区域从图像的左上角开始，但是使用 -2 作为右下角坐标是特殊的。
            //在 Halcon 中，设置坐标为 -2 通常用于告诉 Halcon 自动计算区域大小，以完全适配窗口的大小。
            //也就是说，使用坐标 0, 0, -2, -2 会导致整个图像自动调整大小以完全填充显示窗口，不管图像的原始尺寸是多少。
            hWindow.SetPart(0, 0, -2, -2);
        }

        /// <summary>
        /// 在 OnApplyTemplate 方法中，实际上是在控件的模板被应用时执行的代码。
        /// </summary>
        public override void OnApplyTemplate()
        {
            //GetTemplateChild 方法用于从控件模板中按名称查找对象。

            txtMsg = (TextBlock)GetTemplateChild("PART_MSG");
            if (GetTemplateChild("PART_SMART") is HSmartWindowControlWPF hSmart)
            {
                //对于 PART_SMART，如果找到 HSmartWindowControlWPF 控件，它被赋给 hSmart 成员变量
                this.hSmart = hSmart;
                //注册其Loaded事件的事件处理器为HSmart_Loaded 方法。
                this.hSmart.Loaded += HSmart_Loaded;
            }

            if (GetTemplateChild("PART_RECT") is MenuItem btnRect)
            {
                //对于 PART_RECT，如果找到一个 MenuItem 控件，它给按钮的 Click 事件附加了一个新的事件处理程序。
                btnRect.Click += btnRect_Click;
            }

            if (GetTemplateChild("PART_Ellipse") is MenuItem btnEllipse)
            {
                btnEllipse.Click += btnEllipse_Click;
            }

            if (GetTemplateChild("PART_Circle") is MenuItem btnCircle)
            { 
                btnCircle.Click += btnCircle_Click;
            }

            if (GetTemplateChild("PART_Region") is MenuItem btnRegion)
            {
                btnRegion.Click += btnRegion_Click;
            }

            if (GetTemplateChild("PART_MASK") is MenuItem btnMask)
            {
                btnMask.Click += btnMask_Click;
            }

            if (GetTemplateChild("PART_Clear") is MenuItem btnClear)
            {
                btnClear.Click += (s,e) => 
                {
                    DrawObjectList.Clear();
                    hWindow.ClearWindow();
                    Display(Image);
                };
            }

            base.OnApplyTemplate();
        }

        /// <summary>
        /// 生成屏蔽区
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMask_Click(object sender, RoutedEventArgs e)
        {
            DrawShape(ShapeType.Region);
        }

        /// <summary>
        /// 绘制区域
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void btnRegion_Click(object sender, RoutedEventArgs e)
        {
            DrawShape(ShapeType.Region);
        }

        /// <summary>
        /// 绘制圆形
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void btnCircle_Click(object sender, RoutedEventArgs e)
        {
            DrawShape(ShapeType.Circle, new HTuple(), new HTuple(), new HTuple());
        }

        /// <summary>
        /// 绘制椭圆
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void btnEllipse_Click(object sender, RoutedEventArgs e)
        {
            DrawShape(ShapeType.Ellipse, new HTuple(), new HTuple(), new HTuple(), new HTuple(), new HTuple());
        }

        /// <summary>
        /// 绘制矩形
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRect_Click(object sender, RoutedEventArgs e)
        {
            DrawShape(ShapeType.Rectangle, new HTuple(), new HTuple(), new HTuple(), new HTuple());
        }

        /// <summary>
        /// 绘制不同形状
        /// </summary>
        /// <param name="shapeType"></param>
        /// <param name="hTuples"></param>
        private async void DrawShape(ShapeType shapeType, params HTuple[] hTuples)
        {
            txtMsg.Text = "按鼠标左键开始绘制，右键结束";
            HObject drawObj = null;
            //生成一个新的空的HALCON图形对象(对drawObj 进行初始化)
            HOperatorSet.GenEmptyObj(out drawObj);
            //设置画笔的颜色为红色。
            HOperatorSet.SetColor(hWindow, "red");
            //意味着这个WPF控件hSmart的自动缩放功能被禁用了，用户将无法改变显示内容的缩放级别。
            hSmart.HZoomContent = HSmartWindowControlWPF.ZoomContent.Off;
            //绘制形状
            await Task.Run(() =>
            {
                switch (shapeType)
                {
                    case ShapeType.Rectangle:
                        {
                            //被调用以实际绘制矩形，并在完成后将矩形的两个对角点的行坐标和列坐标保存到之前声明的变量中（row1、column1、row2、column2）。
                            HOperatorSet.DrawRectangle1(hWindow, out hTuples[0], out hTuples[1], out hTuples[2], out hTuples[3]);
                            drawObj = hTuples.GenRectangle();
                            break;
                        }
                    case ShapeType.Ellipse:
                        {
                            HOperatorSet.DrawEllipse(hWindow, out hTuples[0], out hTuples[1], out hTuples[2], out hTuples[3], out hTuples[4]);
                            drawObj = hTuples.GenEllipse();
                            break;
                        }
                        
                    case ShapeType.Circle:
                        {
                            HOperatorSet.DrawCircle(hWindow, out hTuples[0], out hTuples[1], out hTuples[2]);
                            drawObj = hTuples.GenCircle();
                            break;
                        }
                    case ShapeType.Region:
                        {
                            HOperatorSet.DrawRegion(out drawObj, hWindow);
                            break;
                        }
                }
            });

            txtMsg.Text = string.Empty;
            hSmart.HZoomContent = HSmartWindowControlWPF.ZoomContent.WheelBackwardZoomsIn;

            if (shapeType == ShapeType.Region)
            {
                MaskObject = drawObj;
            }

            //drawObj为空，表示没有生成一个HALCON对象rectObj就按右键结束
            else if (drawObj != null)
            {
                //创建了一个新的DrawingObjectInfo对象，并加入到DrawObjectList列表中。这个对象包含了矩形的形状类型和关联的HTuple数组，数组中包含了用于定义矩形的四个坐标值。
                DrawObjectList.Add(new DrawingObjectInfo()
                {
                    ShapeType = shapeType,
                    HTuples = hTuples,
                    HObject = drawObj,
                });

                //获取绘制图像的轮廓
                HOperatorSet.GenContourRegionXld(drawObj, out HObject contours, "border");
                //这行代码的作用是在HALCON的图形显示窗口(hWindow)中显示一个图像或图形对象(drawObj)。
                HOperatorSet.DispObj(contours, hWindow);
            }
        }

        //当HSmartWindowControlWPF (即hSmart)控件加载完成后，HSmart_Loaded方法会被调用。
        private void HSmart_Loaded(object sender, RoutedEventArgs e)
        {
            this.hWindow = this.hSmart.HalconWindow;
        }
    }
}
